﻿#pragma once
#include <AsException.h>
#include <vector>

template <typename _Key, typename _Value>
class AsVectorMap {
public:
	AsVectorMap();

private:
	std::vector<std::pair<_Key, _Value>> mVecMap;

public:
	void resize(int n);
	void insert(const _Key& key, const _Value& value);
	void insert_prior(const _Key& posKey, const _Key& insKey, const _Value& value);
	void insert_next(const _Key& posKey, const _Key& insKey, const _Value& value);
	void insert_indexPrior(int index, const _Key& key, const _Value& value);
	void insert_indexNext(int index, const _Key& key, const _Value& value);
	void remove(const _Key& key);
	void remove_byIndex(int index);
	void remove_byValue(const _Value& value);
	void clear();

public:
	bool isEmpty() const;
	int size() const;
	
public:
	bool contains(const _Key& key) const;
	const _Value& at(const _Key& key) const;
	_Key& indexKey(int index);
	_Value& indexValue(int index);
	const _Key& indexKey(int index) const;
	const _Value& indexValue(int index) const;
	std::vector<_Key> keys() const;
	std::vector<_Value> values() const;

public:
	_Value& operator[](const _Key& key);

};

template <typename _Key, typename _Value>
AsVectorMap<_Key, _Value>::AsVectorMap() {}

template <typename _Key, typename _Value>
void AsVectorMap<_Key, _Value>::resize(int n) {
	mVecMap.resize(n);
}

template <typename _Key, typename _Value>
void AsVectorMap<_Key, _Value>::insert(const _Key& key, const _Value& value) {
	mVecMap.push_back(std::pair<_Key, _Value>(key, value));
}

template <typename _Key, typename _Value>
void AsVectorMap<_Key, _Value>::insert_prior(const _Key& posKey, const _Key& insKey, const _Value& value) {
	for (auto it = mVecMap.begin(); it != mVecMap.end(); it++) {
		if (it->first == posKey) {
			mVecMap.insert(it, std::make_pair(insKey, value));
			break;
		}
	}
}

template <typename _Key, typename _Value>
void AsVectorMap<_Key, _Value>::insert_next(const _Key& posKey, const _Key& insKey, const _Value& value) {
	for (auto it = mVecMap.begin(); it != mVecMap.end(); it++) {
		if (it->first == posKey) {
			mVecMap.insert(++it, std::make_pair(insKey, value));
			break;
		}
	}
}

template <typename _Key, typename _Value>
void AsVectorMap<_Key, _Value>::insert_indexPrior(int index, const _Key& key, const _Value& value) {
	auto it = mVecMap.begin();
	for (int i = 0; i < index && it != mVecMap.end(); i++) it++;
	if (it == mVecMap.end()) return;
	mVecMap.insert(++it, std::make_pair(key, value));
}

template <typename _Key, typename _Value>
void AsVectorMap<_Key, _Value>::insert_indexNext(int index, const _Key& key, const _Value& value) {
	auto it = mVecMap.begin();
	for (int i = 0; i <= index && it != mVecMap.end(); i++) it++;
	if (it == mVecMap.end()) return;
	mVecMap.insert(++it, std::make_pair(key, value));
}

template <typename _Key, typename _Value>
void AsVectorMap<_Key, _Value>::remove(const _Key& key) {
	for (auto it = mVecMap.begin(); it != mVecMap.end(); it++) {
		if (it->first == key) {
			mVecMap.erase(it);
			break;
		}
	}
}

template <typename _Key, typename _Value>
void AsVectorMap<_Key, _Value>::remove_byIndex(int index) {
	auto it = mVecMap.begin();
	for (int i = 0; i < index && it != mVecMap.end(); i++) it++;
	if (it == mVecMap.end()) return;
	mVecMap.erase(it);
}

template <typename _Key, typename _Value>
void AsVectorMap<_Key, _Value>::remove_byValue(const _Value& value) {
	for (auto it = mVecMap.begin(); it != mVecMap.end(); it++) {
		if (it->second == value) {
			mVecMap.erase(it);
			break;
		}
	}
}

template <typename _Key, typename _Value>
void AsVectorMap<_Key, _Value>::clear() {
	mVecMap.clear();
}

template <typename _Key, typename _Value>
bool AsVectorMap<_Key, _Value>::isEmpty() const {
	return mVecMap.empty();
}

template <typename _Key, typename _Value>
int AsVectorMap<_Key, _Value>::size() const {
	return mVecMap.size();
}

template <typename _Key, typename _Value>
bool AsVectorMap<_Key, _Value>::contains(const _Key& key) const {
	for (auto it = mVecMap.begin(); it != mVecMap.end(); it++) {
		if (it->first == key) {
			return true;
		}
	}
	return false;
}

template <typename _Key, typename _Value>
const _Value& AsVectorMap<_Key, _Value>::at(const _Key& key) const {
	for (auto it = mVecMap.begin(); it != mVecMap.end(); it++) {
		if (it->first == key) {
			return it->second;
		}
	}
	return *(new _Value);
}

template <typename _Key, typename _Value>
_Key& AsVectorMap<_Key, _Value>::indexKey(int index) {
	if (index < 0 || index >= mVecMap.size()) throw AsException(AsException::CodeVectorMap_IndexOutOfRange, "index out of range: " + std::to_string(index));
	return mVecMap[index].first;
}

template <typename _Key, typename _Value>
_Value& AsVectorMap<_Key, _Value>::indexValue(int index) {
	if (index < 0 || index >= mVecMap.size()) throw AsException(AsException::CodeVectorMap_IndexOutOfRange, "index out of range: " + std::to_string(index));
	return mVecMap[index].second;
}

template <typename _Key, typename _Value>
const _Key& AsVectorMap<_Key, _Value>::indexKey(int index) const {
	if (index < 0 || index >= mVecMap.size()) throw AsException(AsException::CodeVectorMap_IndexOutOfRange, "index out of range: " + std::to_string(index));
	return mVecMap[index].first;
}

template <typename _Key, typename _Value>
const _Value& AsVectorMap<_Key, _Value>::indexValue(int index) const {
	if (index < 0 || index >= mVecMap.size()) throw AsException(AsException::CodeVectorMap_IndexOutOfRange, "index out of range: " + std::to_string(index));
	return mVecMap[index].second;
}

template <typename _Key, typename _Value>
std::vector<_Key> AsVectorMap<_Key, _Value>::keys() const {
	std::vector<_Key> f_keys;
	f_keys.reserve(mVecMap.size());
	for (auto it = mVecMap.begin(); it != mVecMap.end(); it++) {
		f_keys.push_back(it->first);
	}
	return f_keys;
}

template <typename _Key, typename _Value>
std::vector<_Value> AsVectorMap<_Key, _Value>::values() const {
	std::vector<_Value> f_keys;
	f_keys.reserve(mVecMap.size());
	for (auto it = mVecMap.begin(); it != mVecMap.end(); it++) {
		f_keys.push_back(it->second);
	}
	return f_keys;
}

template <typename _Key, typename _Value>
_Value& AsVectorMap<_Key, _Value>::operator[](const _Key& key) {
	for (auto it = mVecMap.begin(); it != mVecMap.end(); it++) {
		if (it->first == key) {
			return it->second;
		}
	}
	return *(new _Value());
}